Skip to content

RC-9 : Port S8714 to python: Dedicated exception assertions should be used instead of "try-catch" with "fail()"#2292

Closed
rombirli wants to merge 4 commits into
masterfrom
rombirli/s8714-dedicated-exception-assertions-instead-of-try-catch-fail
Closed

RC-9 : Port S8714 to python: Dedicated exception assertions should be used instead of "try-catch" with "fail()"#2292
rombirli wants to merge 4 commits into
masterfrom
rombirli/s8714-dedicated-exception-assertions-instead-of-try-catch-fail

Conversation

@rombirli

@rombirli rombirli commented Jun 22, 2026

Copy link
Copy Markdown

Summary by Gitar

  • New inspection rule:
    • Added DedicatedExceptionAssertionCheck (S8714) to flag try-except blocks paired with fail() calls in tests.
    • Updated OpenSourceCheckList and enabled the rule in both Sonar_way_profile and Sonar_agentic_AI_profile.
  • Rule metadata:
    • Created rule specification files S8714.json and S8714.html detailing noncompliant vs. compliant patterns for pytest and unittest.
  • Test coverage:
    • Added dedicatedExceptionAssertion.py to test various scenarios and DedicatedExceptionAssertionCheckTest for validation.

This will update automatically on new commits.

@rombirli rombirli requested a review from joke1196 June 22, 2026 14:26
@rombirli rombirli closed this Jun 22, 2026
@rombirli rombirli deleted the rombirli/s8714-dedicated-exception-assertions-instead-of-try-catch-fail branch June 22, 2026 14:30
@gitar-bot

gitar-bot Bot commented Jun 22, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 2 resolved / 2 findings

Implements rule S8714 to enforce dedicated exception assertions in tests, resolving issues where the rule previously ignored its own noncompliant examples and provided misleading messages in multi-except blocks.

✅ 2 resolved
Bug: Rule misses its own documented noncompliant examples

📄 python-checks/src/main/java/org/sonar/python/checks/tests/DedicatedExceptionAssertionCheck.java:53-67 📄 python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S8714.html:34-48 📄 python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S8714.html:92-106
The check only fires when (a) fail() is the sole statement of an else clause, or (b) fail() is the last statement of the try body — and in both cases hasSimpleExceptClauses additionally requires every except clause body to be empty (only pass, a docstring, or ... per CheckUtils.isEmptyStatement).

None of the four noncompliant examples in S8714.html match these conditions:

  1. Examples 1 & 3 ("no exception expected") put fail() inside the except clause:
try:
    self.user_service.register_user(self.valid_user)
except ValidationError:
    self.fail("Should not have thrown any exception")  # Noncompliant

The check never inspects fail() calls located in an except body (and the test test_no_issue_when_fail_is_in_except explicitly treats this as compliant), so this pattern is not detected.

  1. Examples 2 & 4 ("exception expected") put fail() as the last statement of the try body but assert on the caught exception in the except clause:
try:
    self.user_service.register_user(self.invalid_user)
    self.fail("Expected ValidationError to be thrown")  # Noncompliant
except ValidationError as e:
    self.assertEqual("Invalid email", str(e))

Because the except body (assertEqual / assert) is not empty, hasSimpleExceptClauses returns false and no issue is raised.

As a result the rule does not flag any of the canonical patterns shown to users in the documentation, which is a significant false-negative gap. Either broaden the detection (handle fail() inside except clauses, and allow non-empty except bodies that perform assertions) or align the HTML examples with the patterns actually detected (the else: fail() shape, which is not even shown in the docs). Adding regression tests mirroring the HTML examples would catch this divergence.

Edge Case: NO_EXCEPTION message misleads when extra except clauses exist

📄 python-checks/src/main/java/org/sonar/python/checks/tests/DedicatedExceptionAssertionCheck.java:58-61 📄 python-checks/src/main/java/org/sonar/python/checks/tests/DedicatedExceptionAssertionCheck.java:77-80
In checkTryStatement, the new loop (lines 58-61) reports NO_EXCEPTION_MESSAGE ("Remove this try/except block and let the test fail naturally if an exception is raised.") for every except clause whose body is a single fail() call. Because hasSupportedExceptClauses was relaxed to accept any number of except clauses (it only requires starToken == null && exception != null), this can fire on a try with multiple except clauses, e.g.:

try:
    risky()
except ValueError:
    self.fail("got ValueError")   # flagged: 'Remove this try/except block'
except TypeError:
    handle()                      # genuinely needed

Here the suggested fix of simply removing the try/except is not actionable without losing the TypeError handling. The same concern applies when the matching except clause contains meaningful recovery logic alongside the action being expected to fail. This is a minor guidance/false-positive edge case rather than a crash; consider only emitting NO_EXCEPTION_MESSAGE when the try statement has a single except clause (and possibly no other fail-bearing branches), or wording the message to acknowledge other clauses.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant